#include "FramePool.hxx"
#include "Sequence.hxx"
#include "VideoThread.hxx"
#include "TrackedObject.hxx"
#include "Project.hxx"
#include "VideoView.hxx"
#include "json.hpp"

#include "SortTrackingThread.hxx"

using json = nlohmann::json;
extern json __appSetting;

SortTrackingThread::SortTrackingThread()
{
}

SortTrackingThread::~SortTrackingThread()
{
}

void SortTrackingThread::initialize()
{
	TrackingThread::initialize();

	std::wstring fileName;

	for (auto& tracker : __appSetting["trackers"]) {
		std::string val = tracker["name"];
		if (strcmp(val.c_str(), _modelType) == 0)
		{
			std::string val = tracker["file"];
			fileName = L"onnx/" + std::wstring(val.begin(), val.end());;
		}
	}

    _detector.setModelFile(fileName);
    _detector.initialize();
}

void SortTrackingThread::run()
{
    std::vector<DetectedObject> detectedObjects;

	if (!isInitialized())
		initialize();

	Sequence* model = getSequence();
	Project* project = model->getVideoView()->getProject();

	int lastObjectId = 0;

	while (1)
	{
		if (getStatus() == TR_STATUS_STOPPED) break;

		if (getStatus() == TR_STATUS_STOPPING)
		{
			setStatus(TR_STATUS_STOPPED);
			break;
		}

		FramePool* inputPool = getInputPool();
		FramePool* outputPool = getOutputPool();
		Sequence* model = getSequence();
		char* frameBuffer = getFrameBuffer();

		if (inputPool->popFrame(frameBuffer))
		{
			int frameIndex = *(int*)frameBuffer;

			static int lastFrameIndex = frameIndex;

			if ((frameIndex < lastFrameIndex) || (frameIndex - lastFrameIndex != 1))
			{
				printf("Error!!!\n");
			}
			lastFrameIndex = frameIndex;

			if (getStatus() == TR_STATUS_TRACKING)
			{
				cv::Mat img(model->getVideoHeight(), model->getVideoWidth(), CV_8UC3, frameBuffer + sizeof(VideoFrameInfo));

				_detector.detect(img, detectedObjects);

				_tracker.update(detectedObjects);

				vector<TrackingBox> boxes = _tracker.getTrackingResults();

				std::vector<TrackedObject*>* objects = model->getTrackingObjects();

				for (int i = 0; i < boxes.size(); i++)
				{
					TrackingBox tbox = boxes.at(i);

					bool existTrack = false;

					TrackedObject* obj = nullptr;

					for (int j = 0; j < objects->size(); j++)
					{
						obj = objects->at(j);

						if (obj->getObjectId() == tbox.id + lastObjectId)
						{
							existTrack = true;
							break;
						}
					}

					cv::Rect2d rect = cv::Rect2d(tbox.box.x, tbox.box.y, tbox.box.width, tbox.box.height);

					if (existTrack)
					{
						Shape* shape = 0;
						ProjectType pt = model->getVideoView()->getProject()->getProjectType();

						if (pt == TYPE_RECTANGLE)
							shape = new ShapeRect(rect);
						else if (pt == TYPE_FISH)
							shape = new ShapeFish(rect);

						obj->setEndFrameIndex(frameIndex);
						obj->pushShape(frameIndex, shape);
					}
					else
					{
						TrackedObject* object = new TrackedObject();
						object->setTemplateBox(rect);
						object->setObjectId(lastObjectId + tbox.id);
						object->setStartFrameIndex(frameIndex);
						object->setEndFrameIndex(frameIndex);
						object->setClassIndex(0);

						objects->push_back(object);

						Shape* shape = 0;
						ProjectType pt = model->getVideoView()->getProject()->getProjectType();

						if (pt == TYPE_RECTANGLE)
							shape = new ShapeRect(rect);
						else if (pt == TYPE_FISH)
							shape = new ShapeFish(rect);

						object->pushShape(frameIndex, shape);
					}
				}
			}

			while (outputPool->isFull())
			{
				msleep(50);
			}

			if (!outputPool->pushFrame(frameBuffer))
			{
				msleep(20);
			}
		}
		else
		{
			msleep(20);
		}
	}
	setStatus(TR_STATUS_STOPPED);
}